#include <fstream>
#include <iostream>
#include <thread>

#include "plog/Initializers/ConsoleInitializer.h"
#include "plog/Initializers/RollingFileInitializer.h"
#include "rapidjson/document.h"
#include <plog/Log.h>

#include "connection.h"
#include "protocal.h"
#include "socket.h"
#include "tcp_server.h"
#include "udp.h"

const char *file_name = "/root/config.json";
const char *default_signal_file_path = "./";
char *server_ip;
uint8_t device_type = 0;
char *signal_file_path;

int main(int argc, char *argv[]) {
    static plog::RollingFileAppender<plog::TxtFormatter> fileAppender("/mnt/uav.log", 8000, 3);
    static plog::ConsoleAppender<plog::TxtFormatter> consoleAppender;
    plog::init(plog::debug, &fileAppender).addAppender(&consoleAppender);
    std::ifstream in(file_name);
    if (!in.is_open()) {
        PLOG_ERROR << "fail to load config.json file.";
        return -1;
    }
    std::string json_content((std::istreambuf_iterator<char>(in)),
                             std::istreambuf_iterator<char>());
    in.close();

    rapidjson::Document dom;
    if (!dom.Parse(json_content.c_str()).HasParseError()) {
        if (dom.HasMember("server address") && dom["server address"].IsString()) {
            server_ip = (char *)dom["server address"].GetString();
            PLOG_INFO << "server ip: " << server_ip;
        } else {
            PLOG_ERROR << "can't parse server address from config file.";
            return -1;
        }
        if (dom.HasMember("device type") && dom["device type"].IsInt()) {
            device_type = (uint8_t)dom["device type"].GetInt();
            PLOG_INFO << "device type code: " << (int)device_type;
        } else {
            PLOG_ERROR << "can't parse device type code from config file. use default code 0.";
            device_type = 0;
        }
        if (dom.HasMember("signal file path") && dom["signal file path"].IsString()) {
            signal_file_path = (char *)dom["signal file path"].GetString();
            PLOG_INFO << "signal file path: " << signal_file_path;
        } else {
            PLOG_ERROR << "can't parse signale file path from config file. use default.";
            signal_file_path = (char *)default_signal_file_path;
        }
    }

    SystemParameters system_parameters;
    Radar radar(signal_file_path);

    /* 建立UDP 服务器 */
    Protocal protocal(device_type, &radar, &system_parameters);
    Udp udp(
        6000, server_ip,
        std::bind(&Protocal::process_msg, &protocal, std::placeholders::_1, std::placeholders::_2));
    protocal.set_send_callback(
        std::bind(&Udp::SendMsg, &udp, std::placeholders::_1, std::placeholders::_2));

    /* 开启感知线程 */
    std::thread sense_thread([&radar]() { radar.senseTask(); });
    std::thread narrow_band_scan_thread([&radar]() { radar.narrowBandScanTask(); });
    std::thread time_sync_thread([&radar]() { radar.timeSyncTask(); });

    /* 建立TCP 服务器 */
    Protocal protocal_for_tcp(device_type, &radar, &system_parameters);
    TcpServer tcp_server(1234);
    tcp_server.onConnect([&protocal_for_tcp](Connection *conn) {
        PLOG_INFO << "New connection fd: " << conn->socket()->fd();
        protocal_for_tcp.set_send_callback(
            std::bind(&Connection::send, conn, std::placeholders::_1, std::placeholders::_2));
    });
    tcp_server.onRecv([&protocal_for_tcp](Connection *conn) {
        protocal_for_tcp.process_msg(reinterpret_cast<const uint8_t *>(conn->read_buf()),
                                     conn->get_recv_len());
    });

    radar.notifyTimeSync();

    /* 开始通讯 */
    std::thread udp_thread([&udp]() { udp.StartCommunication(); });
    tcp_server.Start();

    return 0;
}
